using System;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Logic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using Wjybxx.Commons.Poet;

namespace IQIGame.Onigao.GamePlay.Editors
{
    public class LvServiceNodeCreateWindow : EditorWindow
    {
        private EnumField EF_ExecutionNodeType;
        private TextField TF_ExecutionNodeName;
        private Button Btn_CreateExecution;
        private Button Btn_FieldAdd;
        private Button Btn_FieldSub;

        private VisualElement VE_FieldList;

        private List<NodeField> fieldList = new List<NodeField>();

        const string Regex_FieldName = @"^[a-zA-Z_][a-zA-Z0-9_]*$";

        static string spece2 = string.Empty.PadLeft(2 * 4);
        static string spece3 = string.Empty.PadLeft(3 * 4);
        static string spece4 = string.Empty.PadLeft(4 * 4);

        [MenuItem("ToolApp/关卡编辑器/服务执行创建", false, 90)]
        static void ShowWindow()
        {
            var wnd = GetWindow<LvServiceNodeCreateWindow>();
            wnd.minSize = new Vector2(200, 400);
            wnd.Show(true);
        }

        public void CreateGUI()
        {
            // Import UXML
            var visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/ScriptS/GamePlay/Editor/LevelEditor/LevelService/Window/LvServiceNodeCreateWindow.uxml");
            VisualElement root = visualTree.Instantiate();
            this.rootVisualElement.Add(root);

            this.EF_ExecutionNodeType = root.Q<EnumField>("EF_ExecutionNodeType");
            this.EF_ExecutionNodeType.Init(ServiceExecutionType.Prefab);

            this.TF_ExecutionNodeName = root.Q<TextField>("TF_ExecutionNodeName");

            this.Btn_CreateExecution = root.Q<Button>("Btn_CreateExecution");
            this.Btn_CreateExecution.clicked += this.OnClickBtnCreateExecution;

            this.Btn_FieldAdd = root.Q<Button>("Btn_FieldAdd");
            this.Btn_FieldSub = root.Q<Button>("Btn_FieldSub");
            this.Btn_FieldAdd.clicked += this.OnClickBtnAdd;
            this.Btn_FieldSub.clicked += this.OnClickBtnSub;

            this.VE_FieldList = root.Q<VisualElement>("VE_FieldList");
        }

        private void OnDisable()
        {
            this.Btn_CreateExecution.clicked -= this.OnClickBtnCreateExecution;
            this.Btn_FieldAdd.clicked -= this.OnClickBtnAdd;
            this.Btn_FieldSub.clicked -= this.OnClickBtnSub;
        }

        #region ClickBtn

        private void OnClickBtnCreateExecution()
        {
            var rType = (ServiceExecutionType)this.EF_ExecutionNodeType.value;

            var rConfigType = Type.GetType($"IQIGame.Onigao.GamePlay.LevelServiceExecutionCustom_" + rType.ToString());
            var bCreateData = rConfigType == null;

            bool parsed = bCreateData
                ? ExecutionBatchInfo.Parse(rType, this.fieldList, out var rBatchInfo)
                : ExecutionBatchInfo.Parse(rType, out rBatchInfo);
            if (parsed && (!bCreateData || this.CreateDataFile(rBatchInfo)))
            {
                this.CreateNodeFile(rBatchInfo);
            }

            #region LevelEditorConst

            var rConstPath = $"Assets/Scripts/GamePlay/Editor/LevelEditor/LevelEditorConst.cs";
            var rConstStr = AssetDatabase.LoadAssetAtPath<TextAsset>(rConstPath)?.text;
            if (rConstStr.Contains($"public const string {rType} = \""))
            {
                // 已经有过的旧变量不再修改
                return;
            }
            string rNodeName = this.TF_ExecutionNodeName.text;
            if (string.IsNullOrEmpty(rNodeName))
            {
                rNodeName = rType.ToString();
            }
            string rConstPattern = "#( )?endregion GenerateConstCode";
            string rNewConst = $"{spece2}public const string {rType} = \"{rNodeName}\";\n# endregion GenerateConstCode\n";
            rConstStr = Regex.Replace(rConstStr, rConstPattern, rNewConst, RegexOptions.Singleline);
            File.WriteAllText(rConstPath, rConstStr);

            #endregion
            AssetDatabase.Refresh();
        }

        private void OnClickBtnAdd()
        {
            this.fieldList.Add(NodeField.Create(this.VE_FieldList));
        }

        private void OnClickBtnSub()
        {
            if (this.fieldList.Count > 0)
            {
                var rItem = this.fieldList[^1];
                this.fieldList.Remove(rItem);
                this.VE_FieldList.Remove(rItem.VE_SelfItem);
            }
        }

        #endregion

        private bool CreateDataFile(ExecutionBatchInfo info)
        {
            var rDataCsName = "LevelServiceExecutionCustom_" + info.executionType;
            var rDataCsPath = $"Assets/Scripts/GamePlay/Editor/LevelEditor/LevelService/ServiceConfig/LevelServiceExecutionCustom.cs";
            var rFileTxt = AssetDatabase.LoadAssetAtPath<TextAsset>(rDataCsPath)?.text;
            if (rFileTxt.Contains($"class {rDataCsName} :"))
            {
                return false;
            }
            var rConfigType = Type.GetType($"IQIGame.Onigao.GamePlay.LevelServiceExecutionCustom_" + info.executionType.ToString());
            if (rConfigType != null)
            {
                return false;
            }
            var rCsTxt = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Scripts/GamePlay/Editor/LevelEditor/LevelService/Window/ExecutionDataTemplate.txt")?.text
                .Replace("{_Type}", info.executionType.ToString());
            var rPropertyStr = "";
            var rFields = info.fields;
            for (int i = 0; i < rFields.Count; i++)
            {
                var rField = rFields[i];
                rPropertyStr += spece3 + $"public {rField.fieldType} {rField.fieldName};\n";
            }
            string rPropertyPattern = @"(?<=# region property\s*).*?(?=# endregion property)";
            string rPropertyReplacement = "\n" + rPropertyStr;
            rCsTxt = Regex.Replace(rCsTxt, rPropertyPattern, rPropertyReplacement, RegexOptions.Singleline);
            string rConstPattern = "#( )?endregion GenerateCode";
            rCsTxt += "\n# endregion GenerateCode";
            rFileTxt = Regex.Replace(rFileTxt, rConstPattern, rCsTxt, RegexOptions.Singleline);
            File.WriteAllText(rDataCsPath, rFileTxt);
            return true;
        }

        private void CreateNodeFile(ExecutionBatchInfo info)
        {
            #region 生成Code文件

            var rNodeCsName = "LevelServiceExecutionNode_" + info.executionType;
            var rNodeCsPath = $"Assets/Scripts/GamePlay/Editor/LevelEditor/LevelService/Node/LevelServiceExecution/{rNodeCsName}.cs";
            var rNodeCs = AssetDatabase.LoadAssetAtPath<TextAsset>(rNodeCsPath)?.text;
            if (!string.IsNullOrEmpty(rNodeCs))
            {
                return;
            }
            rNodeCs = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/Scripts/GamePlay/Editor/LevelEditor/LevelService/Window/ExecutionNodeTemplate.txt")?.text
                .Replace("{_Type}", info.executionType.ToString());

            var rPropertyStr = "";
            var rCreateConfigStr = spece3 + $"rConfig = new LevelServiceExecutionCustom_{info.executionType.ToString()}\n" + spece3 + "{\n";
            var rOnSyncStr = spece3 + $"if (tempNode is LevelServiceExecutionNode_{info.executionType.ToString()} rNode)" + "\n" + spece3 + "{\n";
            bool bHasDynamic = false;
            var rFields = info.fields;
            for (int i = 0; i < rFields.Count; i++)
            {
                var rField = rFields[i];
                if (rField.fieldType != "EditorLevelServiceDynamicConfig")
                {
                    rPropertyStr += spece2 + $"[LevelServiceEditorCustomProperty(ServiceExecutionType.{info.executionType.ToString()}, \"{rField.inspectorName}\")]\n";
                    rPropertyStr += spece2 + $"public {rField.fieldType} {rField.fieldName};\n";
                    rCreateConfigStr += spece4 + $"{rField.fieldName} = this.{rField.fieldName},\n";
                    rOnSyncStr += spece4 + $"this.{rField.fieldName} = rNode.{rField.fieldName};\n";
                }
                else
                {
                    rPropertyStr += spece2 + "[Output(\"目标\", false)] public EditorLevelServiceTargetSetter tagOrMcid;\n";
                    bHasDynamic = true;
                }
            }
            rCreateConfigStr += spece3 + "};\n";
            rOnSyncStr += spece3 + "}\n";
            if (bHasDynamic)
            {
                rOnSyncStr += spece3 + $"if (newConfig.customConfig is LevelServiceExecutionCustom_{info.executionType} rConfig)" + "\n" + spece3 + "{\n";
                rOnSyncStr += spece4 + "this.SyncTarget(rConfig.tagOrMcid, nameof(tagOrMcid));\n";
                rOnSyncStr += spece3 + "}\n";
                rCreateConfigStr += spece3 + "this.tagOrMcid = new EditorLevelServiceTargetSetter((x) => rConfig.tagOrMcid = x);\n";
            }

            string rPropertyPattern = @"(?<=# region property\s*).*?(?=# endregion property)";
            string rPropertyReplacement = "\n" + rPropertyStr;
            rNodeCs = Regex.Replace(rNodeCs, rPropertyPattern, rPropertyReplacement, RegexOptions.Singleline);

            string rCreateConfigPattern = @"(?<=# region CreateConfig\s*).*?(?=# endregion CreateConfig)";
            string rCreateConfigReplacement = "\n" + rCreateConfigStr;
            rNodeCs = Regex.Replace(rNodeCs, rCreateConfigPattern, rCreateConfigReplacement, RegexOptions.Singleline);

            string rOnSyncPattern = @"(?<=# region OnSync\s*).*?(?=# endregion OnSync)";
            string rOnSyncReplacement = "\n" + rOnSyncStr;
            rNodeCs = Regex.Replace(rNodeCs, rOnSyncPattern, rOnSyncReplacement, RegexOptions.Singleline);

            File.WriteAllText(rNodeCsPath, rNodeCs);

            #endregion
        }

        public class NodeField
        {
            public VisualElement VE_SelfItem;
            public EnumField EF_FieldType;
            public TextField TF_FieldName;
            public TextField TF_FieldInspectorName;

            public static NodeField Create(VisualElement parent)
            {
                var rNode = new NodeField();
                rNode.VE_SelfItem = new VisualElement();

                rNode.EF_FieldType = new EnumField("属性类型");
                rNode.EF_FieldType.Init(EFieldType.Int);
                rNode.VE_SelfItem.Add(rNode.EF_FieldType);

                rNode.TF_FieldName = new TextField("属性名");
                rNode.VE_SelfItem.Add(rNode.TF_FieldName);

                rNode.TF_FieldInspectorName = new TextField("属性展示名");
                rNode.VE_SelfItem.Add(rNode.TF_FieldInspectorName);

                rNode.VE_SelfItem.style.paddingTop = 8;
                parent.Add(rNode.VE_SelfItem);
                return rNode;
            }

            public bool Parse(out ExecutionFieldInfo info)
            {
                info = null;
                var rFieldName = this.TF_FieldName.text;
                if (!Regex.IsMatch(rFieldName, Regex_FieldName))
                {
                    return false;
                }
                var rFieldTypeStr = (EFieldType)this.EF_FieldType.value switch
                {
                    EFieldType.Int => "int",
                    EFieldType.Bool => "bool",
                    EFieldType.Float => "float",
                    EFieldType.String => "string",
                    EFieldType.EditorLevelServiceDynamicConfig => "EditorLevelServiceDynamicConfig",
                    _ => ""
                };
                if (string.IsNullOrEmpty(rFieldTypeStr))
                {
                    return false;
                }
                var rInspectorName = this.TF_FieldInspectorName.text;
                if (string.IsNullOrEmpty(rInspectorName))
                {
                    rInspectorName = rFieldName;
                }
                info = new ExecutionFieldInfo()
                {
                    fieldType = rFieldTypeStr,
                    fieldName = rFieldName,
                    inspectorName = rInspectorName
                };
                return true;
            }
        }

        public class ExecutionFieldInfo
        {
            public string fieldType;
            public string fieldName;
            public string inspectorName;
        }

        public class ExecutionBatchInfo
        {
            public ServiceExecutionType executionType;
            public List<ExecutionFieldInfo> fields = new List<ExecutionFieldInfo>();

            public static bool Parse(ServiceExecutionType executionType, List<NodeField> nodes, out ExecutionBatchInfo info)
            {
                info = new ExecutionBatchInfo()
                {
                    executionType = executionType
                };
                for (int i = 0; i < nodes.Count; i++)
                {
                    var rNode = nodes[i];
                    if (rNode.Parse(out var rNodeInfo))
                    {
                        info.fields.Add(rNodeInfo);
                    }
                }
                return true;
            }

            public static bool Parse(ServiceExecutionType executionType, out ExecutionBatchInfo info)
            {
                info = new ExecutionBatchInfo()
                {
                    executionType = executionType,
                };
                var rConfigType = Type.GetType($"IQIGame.Onigao.GamePlay.LevelServiceExecutionCustom_" + executionType.ToString());
                if (rConfigType == null)
                {
                    LogGame.LogError("未找到对应类型的配置");
                    return false;
                }
                var rFields = rConfigType.GetFields();
                for (int i = 0; i < rFields.Length; i++)
                {
                    var rField = rFields[i];
                    var rFieldInfo = new ExecutionFieldInfo()
                    {
                        fieldType = TypeName.Get(rField.FieldType).Internal_Keyword,
                        fieldName = rField.Name,
                        inspectorName = rField.Name
                    };
                    info.fields.Add(rFieldInfo);
                }
                return true;
            }
        }


        public enum EFieldType
        {
            Int,
            Float,
            String,
            Bool,
            EditorLevelServiceDynamicConfig
        }
    }
}